package middleware

import (
	"context"
	"errors"
	"net/http"

	"happy-sudoku/internal/codec"
	logging "happy-sudoku/internal/infr"
	"happy-sudoku/internal/model"
	"happy-sudoku/internal/service"

	"github.com/99designs/gqlgen/handler"
)

// AuthMiddleware decodes the share session cookie and packs the session into context
func AuthMiddleware(authSrv service.IAuthService) func(http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			tokenStr := r.Header.Get("Authorization")

			// Allow unauthenticated users in
			if tokenStr == "" || tokenStr == `""` {
				next.ServeHTTP(w, r)
				return
			}

			auth, err := authSrv.ValidateTokenAndGet(tokenStr)

			if err != nil {
				logger := logging.ForLoggerContext(r.Context())
				logger.WithError(err).Error("Jwt token")
				// dipatch to resolver, it will handle auth and permission denied
				// The auth will be identified from context
				authn := model.MakeAuth()
				auth = &authn
				auth.AddError(codec.ErrNotLogin)
				auth.PlayerID = -1
			}

			// put it in context
			ctx := model.WithAuthContext(r.Context(), *auth)
			ctx = logging.WithField(ctx, "PlayerID", auth.PlayerID)

			// and call the next with our new context
			r = r.WithContext(ctx)
			next.ServeHTTP(w, r)
		})
	}
}

// AuthWsMiddleware decodes the share session cookie and packs the session into context
func AuthWsMiddleware(authSrv service.IAuthService) func(ctx context.Context, initPayload handler.InitPayload) (context.Context, error) {
	return func(ctx context.Context, initPayload handler.InitPayload) (context.Context, error) {
		tokenStri, ok := initPayload["authorization"]

		// Allow unauthenticated users in
		if !ok {
			return ctx, nil
		}

		tokenStr, ok := tokenStri.(string)
		// convert not ok
		if !ok {
			return ctx, errors.New("Authorization must be string")
		}

		// Allow unauthenticated users in
		if tokenStr == "" || tokenStr == `""` {
			return ctx, nil
		}

		auth, err := authSrv.ValidateTokenAndGet(tokenStr)

		if err != nil {
			logger := logging.ForLoggerContext(ctx)
			logger.WithError(err).Error("Jwt token")
			// dipatch to resolver, it will handle auth and permission denied
			// The auth will be identified from context
			authn := model.MakeAuth()
			auth = &authn
			// Add Not Login Error
			auth.AddError(codec.ErrNotLogin)
			auth.PlayerID = -1
		}

		// put it in context
		ctxn := model.WithAuthContext(ctx, *auth)
		ctxn = logging.WithField(ctxn, "PlayerID", auth.PlayerID)

		// and call the next with our new context
		return ctxn, nil
	}
}
